﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using XLua;
using Object = UnityEngine.Object;

namespace Al_FrameWork
{
    /// <summary>
    /// 资源加载管理类 1
    /// </summary>
    [Hotfix]
    [LuaCallCSharp]
    public class ResourceManager : MonoBehaviour
    {
        /// <summary>
        /// _instance
        /// </summary>
        private static ResourceManager _instance;

        // asset name  --> assetBundle name
        /// <summary>
        /// assetsMapDic
        /// </summary>
        private readonly Dictionary<string, string> assetsMapDic = new Dictionary<string, string>();

        /// <summary>
        /// loadAssetBundles
        /// </summary>
        private readonly Dictionary<string, AssetBundle> loadAssetBundles = new Dictionary<string, AssetBundle>();

        /// <summary>
        /// LoadSceneCoroutine
        /// </summary>
        private Coroutine loadSceneCoroutine;

        /// <summary>
        /// ResourceManager
        /// </summary>
        public static ResourceManager Instance => GlobalFunctions.GetInstance(ref _instance, "_ResourceManager");

        /// <summary>
        /// 添加AssetBundle
        /// </summary>
        /// <param name="ab"></param>
        public void AddAssetBundle(AssetBundle ab)
        {
            if (!loadAssetBundles.ContainsKey(ab.name))
            {
                loadAssetBundles.Add(ab.name, ab);
            }
        }

        /// <summary>
        /// 获取AssetBundle
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public AssetBundle GetAssetBundle(string name)
        {
            if (loadAssetBundles.ContainsKey(name)) return loadAssetBundles[name];
            return null;
        }

        /// <summary>
        /// 加载场景=>LoadSceneHandler
        /// </summary>
        /// <param name="sceneName"></param>
        IEnumerator LoadSceneHandler(string sceneName, Action callback = null, bool isAsnc = false)
        {
            if (!GetAssetBundle(GameConfig.SceneAssetBundleName))
            {
                AssetBundleCreateRequest assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(Path.Combine(
                    GlobalFunctions.GetPersistentDataPath(),
                    GameConfig.SceneAssetBundleName));
                yield return assetBundleCreateRequest;
                if (assetBundleCreateRequest.isDone)
                {
                    AddAssetBundle(assetBundleCreateRequest.assetBundle);
                    if (isAsnc)
                    {
                        AsyncOperation async = SceneManager.LoadSceneAsync(sceneName);
                        yield return async;
                        if (async.isDone)
                        {
                            callback?.Invoke();
                        }
                    }
                    else
                    {
                        SceneManager.LoadScene(sceneName);
                    }
                }
                else
                {
                    GlobalFunctions.Err("加载出错{0}", sceneName);
                }
            }
            else
            {
                if (isAsnc)
                {
                    AsyncOperation async = SceneManager.LoadSceneAsync(sceneName);
                    yield return async;
                    if (async.isDone)
                    {
                        callback?.Invoke();
                    }
                }
                else
                {
                    SceneManager.LoadScene(sceneName);
                }
            }

            if (loadSceneCoroutine != null)
            {
                StopCoroutine(loadSceneCoroutine);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sceneName"></param>
        /// <param name="callback"></param>
        /// <param name="isAsnc"></param>
        public void LoadScene(string sceneName, Action callback = null, bool isAsnc = false)
        {
            if (loadSceneCoroutine != null)
            {
                StopCoroutine(loadSceneCoroutine);
            }

            loadSceneCoroutine = StartCoroutine(LoadSceneHandler(sceneName, callback, isAsnc));
        }

        /// <summary>
        /// DeleteAssetBundle
        /// </summary>
        /// <param name="name"></param>
        public void DeleteAssetBundle(string name)
        {
            if (loadAssetBundles.ContainsKey(name))
            {
                loadAssetBundles[name].Unload(true);
                loadAssetBundles.Remove(name);
            }
        }

        /// <summary>
        ///  初始化asset name与assetbundle name 映射表
        /// </summary>
        public void InitAssetsMap()
        {
            var name = GlobalFunctions.PackagePathToAssetsPath(GameConfig.AssetsPathMapFileName);
            name = GlobalFunctions.AssetBundlePathToAssetBundleName(name);
            var path = GlobalFunctions.GetPersistentDataPath(name);
            var assetsMap = GetAssetBundle(name);
            if (assetsMap == null)
            {
                Debug.LogError("get assetsMap assetBundle error!");
                return;
            }

            var assetMapText = assetsMap.LoadAsset<TextAsset>(GameConfig.AssetsPathMapFileName);
            var content = assetMapText.text;
            if (string.IsNullOrEmpty(content))
            {
                Debug.LogError("assetsMap empty!");
                return;
            }

            content = content.Replace("\r\n", "\n");
            var maps = content.Split('\n');
            foreach (var map in maps)
            {
                if (string.IsNullOrEmpty(map)) continue;
                var strArr = map.Split(GameConfig.CommonMapPattern);
                if (strArr.Length < 2)
                {
                    Debug.LogError("assetmap item length < 2 : " + map);
                    continue;
                }

                // asset -->  assetBundle name
                assetsMapDic[strArr[1]] = strArr[0];
            }

            Debug.Log("init assetsMap over!");
        }


        /// <summary>
        /// LoadSprite
        /// </summary>
        /// <param name="spriteName"></param>
        /// <returns></returns>
        public Sprite LoadSprite(string spriteName)
        {
            if (assetsMapDic.ContainsKey(spriteName))
            {
                var assetBundleName = assetsMapDic[spriteName];

                var assetBundle = GetAssetBundle(assetBundleName);
                if (assetBundle != null)
                {
                    spriteName = string.Format("Assets/{0}/{1}", GameConfig.AssetsFolderName, spriteName);
                    return assetBundle.LoadAsset<Sprite>(spriteName);
                }
            }

            return null;
        }
        
        /// <summary>
        /// 加载图集
        /// </summary>
        /// <param name="spriteName">从目录Textures开始的相对路径</param>
        /// <returns></returns>
        public Sprite[] LoadSpriteAtlas(string spriteName)
        {
            AssetBundle assetBundle = GetAssetBundle(GameConfig.TexturesAssetBundleName);
            if (assetBundle!=null)
            {
                string url = string.Format("Assets/{0}/{1}/{2}", GameConfig.AssetsFolderName, GameConfig.TexturesFolder,
                    spriteName);
                Sprite []  sprites =  assetBundle.LoadAssetWithSubAssets<Sprite>(url);
                return sprites;
            }

            return null;
        }

        /// <summary>
        /// 卸载所有加载的AssetBundle
        /// </summary>
        public void ClearAllAssetBundle()
        {
            foreach (var items in loadAssetBundles)
            {
                if (items.Value != null) items.Value.Unload(true);
            }

            loadAssetBundles.Clear();
        }

        /// <summary>
        ///     加载资源
        /// </summary>
        /// <param name="assetName"></param>
        /// <returns></returns>
        public Object LoadAsset(string assetName)
        {
            if (assetsMapDic.ContainsKey(assetName))
            {
                var assetBundleName = assetsMapDic[assetName];

                var assetBundle = GetAssetBundle(assetBundleName);
                if (assetBundle != null)
                {
                    assetName = string.Format("Assets/{0}/{1}", GameConfig.AssetsFolderName, assetName);
                    return assetBundle.LoadAsset(assetName);
                }
            }

            return null;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="assetName"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public IEnumerator LoadAssetAsync(string assetName, Action<Object> callback)
        {
            if (assetsMapDic.ContainsKey(assetName))
            {
                string assetBundleName = assetsMapDic[assetName];
                AssetBundle assetBundle = GetAssetBundle(assetBundleName);

                if (assetBundle != null)
                {
                    assetName = string.Format("Assets/{0}/{1}", GameConfig.AssetsFolderName, assetName);
                    AssetBundleRequest request = assetBundle.LoadAssetAsync<Object>(assetName);
                    yield return request;
                    if (request != null && request.isDone)
                    {
                        callback(request.asset);
                    }
                    else
                    {
                        callback(null);
                    }
                }
                else
                {
                    callback(null);
                }
            }
        }


        /// <summary>
        /// LoadAssetWithSubAssets
        /// </summary>
        /// <param name="assetName</param>
        /// <returns></returns>
        public Object[] LoadAssetWithSubAssets(string assetName)
        {
            if (assetsMapDic.ContainsKey(assetName))
            {
                string assetBundleName = assetsMapDic[assetName];
                AssetBundle assetBundle = GetAssetBundle(assetBundleName);
                if (assetBundle != null)
                {
                    assetName = string.Format("Assets/{0}/{1}", GameConfig.AssetsFolderName, assetName);
                    return assetBundle.LoadAssetWithSubAssets(assetName);
                }
            }

            return null;
        }
    }
}